﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Opo.Net.Mail;
using Ninject.Core;

namespace Opo.Perspective.Core
{
    /// <summary>
    /// Represents a mail cache that stores the messages in XML format
    /// </summary>
    public class XmlMailCache : MailCache, IRepository<Message>
    {
        /// <summary>
        /// Gets or sets the path to the mail cache file.
        /// </summary>
        /// <value>Path to the mail cache file.</value>
        public string MailCacheFile { get; set; }
        public string MailBoxPath { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="XmlMailCache"/> class.
        /// </summary>
        /// <param name="parameters">Specifies the path to the mail cache xml file (MailCache.xml).</param>
        public XmlMailCache(IMailStore mailStore, IPerspectivePipeline<IPerspectiveEntity> pipeline, string mailCacheFile)
            : base(mailStore, pipeline)
        {
            if (String.IsNullOrEmpty(mailCacheFile))
            {
                throw new ArgumentNullException("You must specify the path to the xml files (args[0])");
            }
            MailCacheFile = mailCacheFile;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="XmlMailCache"/> class.
        /// </summary>
        /// <param name="parameters">Specifies the path to the mail cache xml file (MailCache.xml).</param>
        public XmlMailCache(IMailStore mailStore, IPerspectivePipeline<IPerspectiveEntity> pipeline, params string[] args)
            : base(mailStore, pipeline)
        {
            if (args.Length == 0)
            {
                throw new ArgumentNullException("You must specify the path to the xml files (args[0])");
            }
            MailCacheFile = args[0];
        }

        /// <summary>
        /// Adds the specified message to the mail cache.
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public override Message Add(Message message)
        {
            // save mail message
            XmlMailMessageConverter xmlConverter = new XmlMailMessageConverter();
            XElement xmlMail = (XElement)xmlConverter.ConvertTo(message);
            xmlMail.Element("mailMessage").Add(new XElement("flag", new XAttribute("type", message.Flag.Type ?? ""), message.Flag.Name));
            xmlMail.Element("mailMessage").Add(new XElement("isRead", message.IsRead));
            xmlMail.Element("mailMessage").Add(new XElement("tags"));
            foreach (var tag in message.Tags.Where(t => !String.IsNullOrEmpty(t.TagName)))
            {
                xmlMail.Descendants("tags").First().Add(new XElement("tag", tag.TagName));
            }
            XDocument xDoc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), xmlMail);
            xDoc.Save(Path.Combine(MailBoxPath, message.ID + ".xml"));

            // save mail cache entry
            XElement mailCacheEntry = SaveMailCacheEntry(message, MailCacheFile);

            return message;
        }
        /// <summary>
        /// Gets the item with the specified MessageID.
        /// </summary>
        /// <param name="id">The message id.</param>
        /// <returns></returns>
        public override Message Get(Guid id)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Gets the items.
        /// </summary>
        /// <returns></returns>
        public override IEnumerable<Message> GetAll()
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Updates the specified message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns></returns>
        public override Message Update(Message message)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Deletes the specified messsage.
        /// </summary>
        /// <param name="messsage">The messsage.</param>
        public override void Delete(Message messsage)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Gets the messageIDs of all messages in the mail cache
        /// </summary>
        /// <returns></returns>
        internal override IEnumerable<string> GetExistingMessageIDs()
        {
            XDocument xDoc = GetMailCacheDocument();
            return from m in xDoc.Descendants("message").Elements("messageID")
                   select m.Value;

        }


        /// <summary>
        /// Gets the mail cache file as XDocument.
        /// </summary>
        /// <returns></returns>
        private XDocument GetMailCacheDocument()
        {
            return XDocument.Load(MailCacheFile);
        }
        /// <summary>
        /// Saves an entry for the message in the mail cache file.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="filePath">The file path of the mail cache file.</param>
        /// <returns></returns>
        private XElement SaveMailCacheEntry(Message message, string filePath)
        {
            XElement xMailMessage = new XElement("MailMessage");
            xMailMessage.Add(new XElement("messageID", message.MessageID));
            xMailMessage.Add(new XElement("uniqueID", message.ID));
            xMailMessage.Add(new XElement("referenceIDs", String.Join(",", message.ReferenceIDs.ToArray())));
            xMailMessage.Add(new XElement("file", Path.GetFileName(filePath)));
            xMailMessage.Add(new XElement("subject", message.Subject));
            xMailMessage.Add(new XElement("date", message.Date.ToString("R")));
            xMailMessage.Add(new XElement("from",
                new XElement("mailAddress",
                    new XAttribute("address", message.From.Address),
                    new XAttribute("displayName", message.From.DisplayName))));
            // attachments
            XElement xAttachments = new XElement("attachments");
            foreach (Attachment attachment in message.Attachments)
            {
                XElement xAttachment = new XElement("attachment");
                xAttachment.Add(new XAttribute("file", attachment.Name));
                xAttachment.Add(new XAttribute("filename", string.Concat(message.MessageID, "_", attachment.Name)));
                xAttachments.Add(xAttachment);
            }
            xMailMessage.Add(xAttachments);
            xMailMessage.Add(new XElement("isRead", message.IsRead.ToString()));
            xMailMessage.Add(new XElement("flag", message.Flag.ToString()));
            // tags
            XElement xTags = new XElement("tags");
            message.Tags.ForEach(t => xTags.Add(new XElement(t.TagName)));
            xMailMessage.Add(xTags);
            return xMailMessage;
        }
    }
}
